#include <Arduino.h>
#include <ArduinoJson.h>
#include "fn_box.h"
#include <set>

// 配置
#define LED_ON HIGH
#define LED_RED PB12
#define LED_GREEN PB13
#define LED_BLUE PB14
#define LED2_RED PA8
#define LED2_GREEN PA9
#define LED2_BLUE PA10

#define BTN_ON LOW
#define BTN_UPLOAD PA0
#define BTN_FORMAT_DISK PA1
#define BTN_UNMOUNT PA2

HardwareTimer timer(TIM1);
auto fn_box = new FnBox();
std::function<void(void)> makeButtonCallback(const char *btn_name, int btn_pin);

// auto btn_name_set = std::set<const char *>();

void setup()
{
  SystemClock_Config();

  SerialUSB.begin(115200);
  // put your setup code here, to run once:
  pinMode(PC13, OUTPUT);

  pinMode(BTN_UPLOAD, INPUT_PULLUP);
  attachInterrupt(BTN_UPLOAD, makeButtonCallback("btn1", BTN_UPLOAD), FALLING);
  pinMode(BTN_FORMAT_DISK, INPUT_PULLUP);
  attachInterrupt(BTN_FORMAT_DISK, makeButtonCallback("btn2", BTN_FORMAT_DISK), FALLING);

  timer.setOverflow(50, MICROSEC_FORMAT);
  timer.attachInterrupt([]
                        { fn_box->scan(); });
  timer.resume();
  // test
  // delay(550);
  fn_box->setInterval(
      "run",
      1000 * 500,
      [](auto name)
      {
        digitalWrite(PC13, !digitalRead(PC13));
        JsonDocument doc;
        doc["fn_id"] = name;
        serializeJson(doc, SerialUSB);
        SerialUSB.println();
      });

  // fn_box->setInterval(
  //     1000 * 1000,
  //     [a](fn_id_t id)
  //     {
  //       JsonDocument doc;
  //       doc["id"] = id;
  //       doc["a"] = a;
  //       serializeJson(doc, SerialUSB);
  //       SerialUSB.println();
  //     });
}

void loop()
{
  // delay(1000);
  // JsonDocument doc;
  // doc["id"] = 1;
  // doc["a"] = 2;
  // serializeJson(doc, SerialUSB);
  // put your main code here, to run repeatedly:
  // digitalWrite(PC13, !digitalRead(PC13));
  // delay(500);
}

std::function<void(void)> makeButtonCallback(const char *btn_name, int btn_pin)
{
  char btn_up[10];
  sprintf(btn_up, "%s_up", btn_name);
  char btn_down[10];
  sprintf(btn_down, "%s_down", btn_name);
  return [=]
  {
    if (fn_box->hasName(btn_name))
      return;
    // if (btn_name_set.find(btn_name) != btn_name_set.end())
    // {
    //   return;
    // }
    // btn_name_set.insert(btn_name);
    auto start_at = millis();
    auto ok = fn_box->setInterval(
        btn_name,
        1000,
        [=](auto name)
        {
          auto is_off = digitalRead(btn_pin) != BTN_ON;
          if (is_off)
          {
            fn_box->clearInterval(name);
            JsonDocument doc;
            // doc["type"] = F("btn2_up");
            doc["type"] = btn_up;
            doc["elapsed"] = millis() - start_at;
            // char test[10];
            // sprintf(test, "%s_up", *btn_name);
            // doc["name"] = btn_down;
            serializeJson(doc, SerialUSB);
            SerialUSB.println();
            // btn_name_set.erase(btn_name);
          }
          // test
          SerialUSB.println();
          //
        });
    JsonDocument doc;
    // doc["type"] = F("btn2_down");
    doc["type"] = btn_down;
    doc["set"] = ok;
    serializeJson(doc, SerialUSB);
    SerialUSB.println();
  };
}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    // Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    // Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    // Error_Handler();
  }
}
